/*
 * Wannafly - http://subsonicproject.com
 * 
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an 
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
*/

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using QuickDev.Common.Utils.Extensions;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Xml;

namespace QuickDev.Common.Utils
{
    /// <summary>
    /// A class containing support methods used internally to Wannafly
    /// </summary>
    public class Utility
    {
        #region URL

        /// <summary>
        /// Gets the parameter.
        /// </summary>
        /// <param name="sParam">The s param.</param>
        /// <returns></returns>
        public static string GetParameter( string sParam )
        {
            if ( HttpContext.Current.Request.QueryString[sParam] != null )
                return HttpContext.Current.Request[sParam];
            return String.Empty;
        }

        /// <summary>
        /// Gets the int parameter.
        /// </summary>
        /// <param name="sParam">The s param.</param>
        /// <returns></returns>
        public static int GetIntParameter( string sParam )
        {
            int iOut = 0;
            if ( HttpContext.Current.Request.QueryString[sParam] != null )
            {
                string sOut = HttpContext.Current.Request[sParam];
                if ( !String.IsNullOrEmpty( sOut ) )
                    int.TryParse( sOut , out iOut );
            }
            return iOut;
        }

        /// <summary>
        /// Gets the site root.
        /// </summary>
        /// <returns></returns>
        public static string SiteRoot
        {
            get
            {
                string port = HttpContext.Current.Request.ServerVariables[ServerVariable.SERVER_PORT];

                if ( port == null || port == Ports.HTTP || port == Ports.HTTPS )
                    port = String.Empty;
                else
                    port = String.Concat( ":" , port );

                string protocol = HttpContext.Current.Request.ServerVariables[ServerVariable.SERVER_PORT_SECURE];
                if ( protocol == null || protocol == "0" )
                    protocol = ProtocolPrefix.HTTP;
                else
                    protocol = ProtocolPrefix.HTTPS;

                string appPath = HttpContext.Current.Request.ApplicationPath;

                if ( appPath == "/" )
                    appPath = String.Empty;

                string sOut = protocol + HttpContext.Current.Request.ServerVariables[ServerVariable.SERVER_NAME] + port + appPath;

                return sOut;
            }
        }

        /// <summary>
        /// Queries the string.
        /// </summary>
        /// <typeparam name="t"></typeparam>
        /// <param name="param">The param.</param>
        /// <returns></returns>
        public static t QueryString<t>( string param )
        {
            t result = default( t );

            if ( HttpContext.Current.Request.QueryString[param] != null )
            {
                object paramValue = HttpContext.Current.Request[param];
                result = (t)Utility.ChangeTypeTo<t>( paramValue );
            }

            return result;
        }

        /// <summary>
        /// Adds and removes keys from the QueryString using the passed in values.
        /// Adding/Updating the <see cref="keyToAdd"/> in the result.
        /// Removing the values that are in <see cref="keysToRemove"/> from the result.
        /// </summary>
        /// <param name="queryString">The query string.</param>
        /// <param name="keyToAdd">The key to add.</param>
        /// <param name="valueToAdd">The value to add.</param>
        /// <param name="keysToRemove">The keys to remove.</param>
        /// <returns>Return a string formated as a QueryString</returns>
        public static string AddRemoveFromQueryString( NameValueCollection queryString , string keyToAdd , string valueToAdd , params string[] keysToRemove )
        {
            StringBuilder queryStringText = new StringBuilder( "?" );
            const string QUERYSTRING_FORMAT = "{0}={1}";
            string currentKey;
            List<string> removeStrings = new List<string>( keysToRemove );

            for ( int i = 0 ; i < queryString.Count ; i++ )
            {
                currentKey = queryString.GetKey( i );
                if ( removeStrings.Contains( currentKey ) || currentKey == keyToAdd )
                    continue;
                queryStringText.Append( string.Format( QUERYSTRING_FORMAT , queryString.GetKey( i ) , queryString.Get( i ) ) );
                queryStringText.Append( "&" );
            }
            queryStringText.Append( string.Format( QUERYSTRING_FORMAT , keyToAdd , valueToAdd ) );
            return queryStringText.ToString();
        }

        /// <summary>
        /// Ensures that the browser is connected using SSL if not it redirects the browser to https://CURRENT_URL.
        /// It does not redirect if the request is coming from the same IP as the site (development mode (i.e. localhost)).
        /// </summary>
        public static void EnsureSsl()
        {
            Uri currentUrl = HttpContext.Current.Request.Url;
            if ( !currentUrl.IsLoopback )
            {//Don't check when in development mode (i.e. localhost)
                if ( !currentUrl.Scheme.Equals( "https" , StringComparison.CurrentCultureIgnoreCase ) && HttpContext.Current.Request.ServerVariables["HTTP_CLUSTER_HTTPS"] != "on" )
                {
                    UriBuilder uriBuilder = new UriBuilder( currentUrl );
                    uriBuilder.Scheme = "https";
                    uriBuilder.Port = -1;
                    HttpContext.Current.Response.Redirect( uriBuilder.Uri.ToString() , true );
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether current connection is secured
        /// </summary>
        /// <returns>true - secured, false - not secured</returns>
        public static bool IsCurrentConnectionSecured()
        {
            bool useSSL = false;
            if ( HttpContext.Current != null && HttpContext.Current.Request != null )
            {
                useSSL = HttpContext.Current.Request.IsSecureConnection;
                //when your hosting uses a load balancer on their server then the Request.IsSecureConnection is never got set to true, use the statement below
                //just uncomment it
                //useSSL = HttpContext.Current.Request.ServerVariables["HTTP_CLUSTER_HTTPS"] == "on" ? true : false;
            }

            return useSSL;
        }

        /// <summary>
        /// Gets this page name
        /// </summary>
        /// <returns></returns>
        public static string GetCurrentPageUrl( bool includeQueryString )
        {
            string URL = string.Empty;
            if ( HttpContext.Current == null )
                return URL;

            if ( includeQueryString )
            {
                bool useSSL = IsCurrentConnectionSecured();
                string url =  SiteRoot;
                if ( url.EndsWith( "/" ) )
                    url = url.Substring( 0 , url.Length - 1 );
                URL = url + HttpContext.Current.Request.RawUrl;
            }
            else
            {
                URL = HttpContext.Current.Request.Url.GetLeftPart( UriPartial.Path );
            }
            URL = URL.ToLowerInvariant();
            return URL;
        }

        /// <summary>
        /// Gets a value indicating whether requested page is an admin page
        /// </summary>
        /// <returns>A value indicating whether requested page is an admin page</returns>
        public static bool IsAdmin()
        {
            string currentPageUrl = GetCurrentPageUrl( false );
            if ( string.IsNullOrEmpty( currentPageUrl ) )
                return false;

            string adminUrl1 = GetStoreLocation( false ) + "administration";
            string adminUrl2 = GetStoreLocation( true ) + "administration";
            bool flag1 = currentPageUrl.ToLowerInvariant().StartsWith( adminUrl1.ToLower() );
            bool flag2 = currentPageUrl.ToLowerInvariant().StartsWith( adminUrl2.ToLower() );
            bool isAdmin = flag1 || flag2;
            return isAdmin;
        }

        /// <summary>
        /// Gets store location
        /// </summary>
        /// <returns>Store location</returns>
        public static string GetStoreLocation()
        {
            bool useSSL = IsCurrentConnectionSecured();
            return GetStoreLocation( useSSL );
        }

        /// <summary>
        /// Gets store location
        /// </summary>
        /// <param name="useSsl">Use SSL</param>
        /// <returns>Store location</returns>
        public static string GetStoreLocation( bool useSsl )
        {
            string result = GetStoreHost( useSsl );
            if ( result.EndsWith( "/" ) )
                result = result.Substring( 0 , result.Length - 1 );
            result = result + HttpContext.Current.Request.ApplicationPath;
            if ( !result.EndsWith( "/" ) )
                result += "/";

            return result.ToLowerInvariant();
        }

        /// <summary>
        /// Gets store admin location
        /// </summary>
        /// <returns>Store admin location</returns>
        public static string GetStoreAdminLocation()
        {
            bool useSSL = IsCurrentConnectionSecured();
            return GetStoreAdminLocation( useSSL );
        }

        /// <summary>
        /// Gets store admin location
        /// </summary>
        /// <param name="useSsl">Use SSL</param>
        /// <returns>Store admin location</returns>
        public static string GetStoreAdminLocation( bool useSsl )
        {
            string result = GetStoreLocation( useSsl );
            result += "Administration/";

            return result.ToLowerInvariant();
        }

        /// <summary>
        /// Removes the QueryString from the URL of the Current Request.
        /// </summary>
        /// <returns></returns>
        public static string ScrubUrl()
        {
            string url = HttpContext.Current.Request.Url.ToString();
            int resultPosition = url.IndexOf( "?" );
            if ( resultPosition > -1 )
            {
                url = url.Substring( 0 , resultPosition );
            }
            return url;
        }

        /// <summary>
        /// Scrub the Host left url of the Request URL.
        /// </summary>
        /// <returns></returns>
        public static string ScrubUrl( string url )
        {
            string result = url;

            result = result.Replace( "http://" , String.Empty );
            result = result.Replace( "https://" , String.Empty );
            result = result.Replace( "www.www" , "www" );

            int resultPosition = result.IndexOf( "/" );
            if ( resultPosition > -1 )
            {
                result = result.Substring( resultPosition );
            }

            return result;
        }

        /// <summary>
        /// Scrub the Host of the Request URL.
        /// </summary>
        /// <returns></returns>
        public static string ScrubHost( string url )
        {
            string result = url;

            result = result.Replace( "http://" , String.Empty );
            result = result.Replace( "https://" , String.Empty );
            result = result.Replace( "www.www" , "www" );

            int resultPosition = result.IndexOf( "/" );
            if ( resultPosition > -1 )
            {
                result = result.Substring( 0 , resultPosition );
            }

            return result;
        }

        /// <summary>
        /// Reloads current page
        /// </summary>
        public static void ReloadCurrentPage()
        {
            ReloadCurrentPage( false );
        }

        /// <summary>
        /// Reloads current page
        /// </summary>
        /// <param name="UseSSL">Use SSL</param>
        public static void ReloadCurrentPage( bool UseSSL )
        {
            string storeHost = GetStoreHost( UseSSL );
            if ( storeHost.EndsWith( "/" ) )
                storeHost = storeHost.Substring( 0 , storeHost.Length - 1 );
            string URL = storeHost + HttpContext.Current.Request.RawUrl;
            try
            {
                HttpContext.Current.Response.Redirect( URL , true );
            }
            catch ( System.Threading.ThreadAbortException )
            {
                //swallow it
            }
        }

        /// <summary>
        /// Gets store host location
        /// </summary>
        /// <param name="UseSSL">Use SSL</param>
        /// <returns>Store host location</returns>
        public static string GetStoreHost( bool UseSSL )
        {
            string result = "http://" + ServerVariables( "HTTP_HOST" );
            if ( !result.EndsWith( "/" ) )
                result += "/";

            if ( UseSSL )
            {
                result = result.Replace( "http:/" , "https:/" );
                result = result.Replace( "www.www" , "www" );
            }

            if ( !result.EndsWith( "/" ) )
                result += "/";

            return result;
        }

        /// <summary>
        /// Modifies query string
        /// </summary>
        /// <param name="url">Url to modify</param>
        /// <param name="queryStringModification">Query string modification</param>
        /// <param name="targetLocationModification">Target location modification</param>
        /// <returns>New url</returns>
        public static string ModifyQueryString( string url , string queryStringModification , string targetLocationModification )
        {
            if ( url == null )
                url = string.Empty;
            url = url.ToLowerInvariant();

            if ( queryStringModification == null )
                queryStringModification = string.Empty;
            queryStringModification = queryStringModification.ToLowerInvariant();

            if ( targetLocationModification == null )
                targetLocationModification = string.Empty;
            targetLocationModification = targetLocationModification.ToLowerInvariant();


            string str = string.Empty;
            string str2 = string.Empty;
            if ( url.Contains( "#" ) )
            {
                str2 = url.Substring( url.IndexOf( "#" ) + 1 );
                url = url.Substring( 0 , url.IndexOf( "#" ) );
            }
            if ( url.Contains( "?" ) )
            {
                str = url.Substring( url.IndexOf( "?" ) + 1 );
                url = url.Substring( 0 , url.IndexOf( "?" ) );
            }
            if ( !string.IsNullOrEmpty( queryStringModification ) )
            {
                if ( !string.IsNullOrEmpty( str ) )
                {
                    var dictionary = new Dictionary<string , string>();
                    foreach ( string str3 in str.Split( new char[] { '&' } ) )
                    {
                        if ( !string.IsNullOrEmpty( str3 ) )
                        {
                            string[] strArray = str3.Split( new char[] { '=' } );
                            if ( strArray.Length == 2 )
                            {
                                dictionary[strArray[0]] = strArray[1];
                            }
                            else
                            {
                                dictionary[str3] = null;
                            }
                        }
                    }
                    foreach ( string str4 in queryStringModification.Split( new char[] { '&' } ) )
                    {
                        if ( !string.IsNullOrEmpty( str4 ) )
                        {
                            string[] strArray2 = str4.Split( new char[] { '=' } );
                            if ( strArray2.Length == 2 )
                            {
                                dictionary[strArray2[0]] = strArray2[1];
                            }
                            else
                            {
                                dictionary[str4] = null;
                            }
                        }
                    }
                    var builder = new StringBuilder();
                    foreach ( string str5 in dictionary.Keys )
                    {
                        if ( builder.Length > 0 )
                        {
                            builder.Append( "&" );
                        }
                        builder.Append( str5 );
                        if ( dictionary[str5] != null )
                        {
                            builder.Append( "=" );
                            builder.Append( dictionary[str5] );
                        }
                    }
                    str = builder.ToString();
                }
                else
                {
                    str = queryStringModification;
                }
            }
            if ( !string.IsNullOrEmpty( targetLocationModification ) )
            {
                str2 = targetLocationModification;
            }
            return ( url + ( string.IsNullOrEmpty( str ) ? "" : ( "?" + str ) ) + ( string.IsNullOrEmpty( str2 ) ? "" : ( "#" + str2 ) ) ).ToLowerInvariant();
        }

        /// <summary>
        /// Remove query string from url
        /// </summary>
        /// <param name="url">Url to modify</param>
        /// <param name="queryString">Query string to remove</param>
        /// <returns>New url</returns>
        public static string RemoveQueryString( string url , string queryString )
        {
            if ( url == null )
                url = string.Empty;
            url = url.ToLowerInvariant();

            if ( queryString == null )
                queryString = string.Empty;
            queryString = queryString.ToLowerInvariant();


            string str = string.Empty;
            if ( url.Contains( "?" ) )
            {
                str = url.Substring( url.IndexOf( "?" ) + 1 );
                url = url.Substring( 0 , url.IndexOf( "?" ) );
            }
            if ( !string.IsNullOrEmpty( queryString ) )
            {
                if ( !string.IsNullOrEmpty( str ) )
                {
                    Dictionary<string, string> dictionary = new Dictionary<string , string>();
                    foreach ( string str3 in str.Split( new char[] { '&' } ) )
                    {
                        if ( !string.IsNullOrEmpty( str3 ) )
                        {
                            string[] strArray = str3.Split( new char[] { '=' } );
                            if ( strArray.Length == 2 )
                            {
                                dictionary[strArray[0]] = strArray[1];
                            }
                            else
                            {
                                dictionary[str3] = null;
                            }
                        }
                    }
                    dictionary.Remove( queryString );

                    var builder = new StringBuilder();
                    foreach ( string str5 in dictionary.Keys )
                    {
                        if ( builder.Length > 0 )
                        {
                            builder.Append( "&" );
                        }
                        builder.Append( str5 );
                        if ( dictionary[str5] != null )
                        {
                            builder.Append( "=" );
                            builder.Append( dictionary[str5] );
                        }
                    }
                    str = builder.ToString();
                }
            }
            return ( url + ( string.IsNullOrEmpty( str ) ? "" : ( "?" + str ) ) );
        }

        #endregion

        #region Cookie

        /// <summary>
        /// Sets cookie
        /// </summary>
        /// <param name="cookieName">Cookie name</param>
        /// <param name="cookieValue">Cookie value</param>
        /// <param name="ts">Timespan</param>
        public static void SetCookie( string cookieName , string cookieValue , TimeSpan ts )
        {
            try
            {
                HttpCookie cookie = new HttpCookie( cookieName );
                cookie.Value = HttpContext.Current.Server.UrlEncode( cookieValue );
                DateTime dt = DateTime.Now;
                cookie.Expires = dt.Add( ts );
                HttpContext.Current.Response.Cookies.Add( cookie );
            }
            catch ( Exception exc )
            {
                Debug.WriteLine( exc.Message );
            }
        }

        /// <summary>
        /// Cookies the specified param.
        /// </summary>
        /// <typeparam name="t"></typeparam>
        /// <param name="param">The param.</param>
        /// <returns></returns>
        public static t Cookie<t>( string param )
        {
            t result = default( t );
            HttpCookie cookie = HttpContext.Current.Request.Cookies[param];
            if ( cookie != null )
            {
                string paramValue = cookie.Value;
                result = (t)Utility.ChangeTypeTo<t>( paramValue );
            }

            return result;
        }

        #endregion

        #region Session

        /// <summary>
        /// Sessions the value.
        /// </summary>
        /// <typeparam name="t"></typeparam>
        /// <param name="param">The param.</param>
        /// <returns></returns>
        public static t SessionValue<t>( string param )
        {
            t result = default( t );
            if ( HttpContext.Current.Session[param] != null )
            {
                object paramValue = HttpContext.Current.Session[param];
                result = (t)Utility.ChangeTypeTo<t>( paramValue );
            }

            return result;
        }

        /// <summary>
        /// WriteSession
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        public static void WriteSession( string key , object value )
        {
            if ( HttpContext.Current.Session[key] != null )
                HttpContext.Current.Session[key] = value;
            else
                HttpContext.Current.Session.Add( key , value );
        }

        /// <summary>
        /// RemoveSession
        /// </summary>
        /// <param name="key">key</param>
        public static void RemoveSession( string key )
        {
            if ( HttpContext.Current.Session[key] != null )
            {
                HttpContext.Current.Session.Remove( key );
            }
            else
            {
                HttpContext.Current.Session[key] = null;
            }
        }

        #endregion

        #region ServerVariables

        /// <summary>
        /// Gets server variable by name
        /// </summary>
        /// <param name="Name">Name</param>
        /// <returns>Server variable</returns>
        public static string ServerVariables( string Name )
        {
            string tmpS = String.Empty;
            try
            {
                if ( HttpContext.Current.Request.ServerVariables[Name] != null )
                {

                    tmpS = HttpContext.Current.Request.ServerVariables[Name].ToString();

                }
            }
            catch
            {
                tmpS = String.Empty;
            }
            return tmpS;
        }

        #endregion

        #region  Page

        //many thanks to ASP Alliance for the code below
        //http://authors.aspalliance.com/olson/methods/

        /// <summary>
        /// Fetches a web page
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        public static string ReadWebPage( string url )
        {
            string webPage;

            try
            {
                WebRequest request = WebRequest.Create( url );
                using ( Stream stream = request.GetResponse().GetResponseStream() )
                {
                    StreamReader sr = new StreamReader( stream );
                    webPage = sr.ReadToEnd();
                    sr.Close();
                }
            }
            catch ( System.Exception ex )
            {
                return ex.ToString();
            }

            return webPage;
        }

        /// <summary>
        /// Return the images links in a given URL as an array of strings.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="returnWithTag">if set to <c>true</c> the string are returned as an XHTML compliant img tag; otherwise returns a list of img URLs only</param>
        /// <returns>string array of all images on a page</returns>
        public static string[] ScrapeImages( string htmlPage , bool returnWithTag )
        {
            //set up the regex for finding images
            StringBuilder imgPattern = new StringBuilder();
            imgPattern.Append( "<img[^>]+" ); //start 'img' tag
            imgPattern.Append( "src\\s*=\\s*" ); //start src property
            //three possibilities  for what src property --
            //(1) enclosed in double quotes
            //(2) enclosed in single quotes
            //(3) enclosed in spaces
            imgPattern.Append( "(?:\"(?<src>[^\"]*)\"|'(?<src>[^']*)'|(?<src>[^\"'>\\s]+))" );
            imgPattern.Append( "[^>]*>" ); //end of tag
            Regex imgRegex = new Regex( imgPattern.ToString() , RegexOptions.IgnoreCase );

            //look for matches 
            Match imgcheck = imgRegex.Match( htmlPage );
            ArrayList imagelist = new ArrayList();

            while ( imgcheck.Success )
            {
                string src = imgcheck.Groups["src"].Value;
                string image = returnWithTag ? "<img src=\"" + src + "\" alt=\"\" />" : src;
                imagelist.Add( image );
                imgcheck = imgcheck.NextMatch();
            }

            string[] images = new string[imagelist.Count];
            imagelist.CopyTo( images );

            return images;
        }

        /// <summary>
        /// Return the images links in a given URL as an array of XHTML-compliant img tags.
        /// </summary>
        /// <param name="url">The URL to extract the images from.</param>
        /// <returns></returns>
        public static string[] ScrapeImages( string url )
        {
            return ScrapeImages( url , true );
        }

        /// <summary>
        /// Scrapes a web page and parses out all the links.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="makeLinkable">if set to <c>true</c> [make linkable].</param>
        /// <returns></returns>
        public static string[] ScrapeLinks( string htmlPage , bool makeLinkable )
        {
            //set up the regex for finding the link urls
            StringBuilder hrefPattern = new StringBuilder();
            hrefPattern.Append( "<a[^>]+" ); //start 'a' tag and anything that comes before 'href' tag
            hrefPattern.Append( "href\\s*=\\s*" ); //start href property
            //three possibilities  for what href property --
            //(1) enclosed in double quotes
            //(2) enclosed in single quotes
            //(3) enclosed in spaces
            hrefPattern.Append( "(?:\"(?<href>[^\"]*)\"|'(?<href>[^']*)'|(?<href>[^\"'>\\s]+))" );
            hrefPattern.Append( "[^>]*>.*?</a>" ); //end of 'a' tag
            Regex hrefRegex = new Regex( hrefPattern.ToString() , RegexOptions.IgnoreCase );

            //look for matches 
            Match hrefcheck = hrefRegex.Match( htmlPage );
            ArrayList linklist = new ArrayList();
            while ( hrefcheck.Success )
            {
                string href = hrefcheck.Groups["href"].Value; //link url
                string link = ( makeLinkable )
                                  ? "<a href=\"" + href + "\" target=\"_blank\">" + href + "</a>"
                                  : href;
                linklist.Add( link );
                hrefcheck = hrefcheck.NextMatch();
            }
            string[] links = new string[linklist.Count];
            linklist.CopyTo( links );

            return links;
        }

        /// <summary>
        /// Calls the Gravatar service to and returns an HTML <img></img> tag for use on your pages.
        /// </summary>
        /// <param name="email">The email of the user</param>
        /// <param name="size">The size of the Gravatar image - 60 is standard</param>
        /// <returns>HTML image tag</returns>
        public static string GetGravatar( string email , int size )
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash( Encoding.ASCII.GetBytes( email ) );

            StringBuilder hash = new StringBuilder();
            for ( int i = 0 ; i < result.Length ; i++ )
                hash.Append( result[i].ToString( "x2" ) );

            StringBuilder image = new StringBuilder();
            image.Append( "<img src=\"" );
            image.Append( "http://www.gravatar.com/avatar.php?" );
            image.Append( "gravatar_id=" + hash );
            image.Append( "&amp;rating=G" );
            image.Append( "&amp;size=" + size );
            image.Append( "&amp;default=" );
            image.Append( HttpContext.Current.Server.UrlEncode( "http://example.com/noavatar.gif" ) );
            image.Append( "\" alt=\"\" />" );
            return image.ToString();
        }

        /// <summary>
        /// Given a valid email address, returns a short javascript block that will emit a valid
        /// mailto: link that can't be picked up by address harvesters. Call this method where you
        /// would normally place the link in your html code.
        /// </summary>
        /// <param name="emailText">The email address to convert to spam-free format</param>
        /// <returns></returns>
        public static string CreateSpamFreeEmailLink( string emailText )
        {
            if ( !String.IsNullOrEmpty( emailText ) )
            {
                string[] parts = emailText.Split( new char[] { '@' } );
                if ( parts.Length == 2 )
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append( "<script type='text/javascript'>" );
                    sb.Append( "var m = '" + parts[0] + "';" );
                    sb.Append( "var a = '" + parts[1] + "';" );
                    sb.Append( "var l = '" + emailText + "';" );
                    sb.Append( "document.write('<a href=\"mailto:' + m + '@' + a + '\">' + l + '</a>');" );
                    sb.Append( "</script>" );
                    return sb.ToString();
                }
            }
            return String.Empty;
        }

        #endregion

        #region Network

        /// <summary>
        /// Whether or not the request originated from the local network, or more specifically from localhost or a NAT address.
        /// This property is only accurate if NAT addresses are a valid indicators of a request being from within the internal network.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is local network request; otherwise, <c>false</c>.
        /// </value>
        public static bool IsLocalNetworkRequest
        {
            get
            {
                if ( HttpContext.Current != null )
                {
                    if ( HttpContext.Current.Request.IsLocal )
                        return true;

                    string hostPrefix = HttpContext.Current.Request.UserHostAddress;
                    string[] ipClass = hostPrefix.Split( new char[] { '.' } );
                    int classA = Convert.ToInt16( ipClass[0] );
                    int classB = Convert.ToInt16( ipClass[1] );

                    if ( classA == 10 || classA == 127 )
                        return true;
                    if ( classA == 192 && classB == 168 )
                        return true;
                    return classA == 172 && ( classB > 15 && classB < 33 );
                }
                return false;
            }
        }

        /// <summary>
        /// get the user ip address
        /// </summary>
        public static string Ip
        {
            get
            {
                string ip;
                HttpRequest Request = HttpContext.Current.Request;

                // if request from remote address, return REMOTE_ADDR
                if ( String.IsNullOrEmpty( Request.ServerVariables[ServerVariable.HTTP_X_FORWARDED_FOR] ) )
                    ip = Request.ServerVariables[ServerVariable.REMOTE_ADDR];
                else
                    ip = Request.ServerVariables[ServerVariable.HTTP_X_FORWARDED_FOR];

                //if ip is null or empty
                if ( String.IsNullOrEmpty( ip ) )
                    ip = Request.UserHostAddress;

                return ip;
            }
        }

        /// <summary>
        /// Gets DNS information about a url and puts it in an array of strings
        /// </summary>
        /// <param name="url">either an ip address or a host name</param>
        /// <returns>
        /// a list with the host name, all the aliases, and all the addresses.
        /// </returns>
        public static string[] DNSLookup( string url )
        {
            ArrayList al = new ArrayList();

            //check whether url is ipaddress or hostname
            IPHostEntry ipEntry = Dns.GetHostEntry( url );

            al.Add( "HostName," + ipEntry.HostName );

            foreach ( string name in ipEntry.Aliases )
                al.Add( "Aliases," + name );

            foreach ( IPAddress ip in ipEntry.AddressList )
                al.Add( "Address," + ip );

            string[] ipInfo = (string[])al.ToArray( typeof( string ) );

            return ipInfo;
        }

        #endregion

        #region Response

        /// <summary>
        /// Write XML to response
        /// </summary>
        /// <param name="xml">XML</param>
        /// <param name="fileName">Filename</param>
        public static void WriteResponseXml( string xml , string fileName )
        {
            if ( !String.IsNullOrEmpty( xml ) )
            {
                XmlDocument document = new XmlDocument();
                document.LoadXml( xml );
                XmlDeclaration decl = document.FirstChild as XmlDeclaration;
                if ( decl != null )
                {
                    decl.Encoding = "utf-8";
                }
                HttpResponse response = HttpContext.Current.Response;
                response.Clear();
                response.Charset = "utf-8";
                response.ContentType = "text/xml";
                response.AddHeader( "content-disposition" , string.Format( "attachment; filename={0}" , fileName ) );
                response.BinaryWrite( Encoding.UTF8.GetBytes( document.InnerXml ) );
                response.End();
            }
        }

        /// <summary>
        /// Write text to response
        /// </summary>
        /// <param name="txt">text</param>
        /// <param name="fileName">Filename</param>
        public static void WriteResponseTxt( string txt , string fileName )
        {
            if ( !String.IsNullOrEmpty( txt ) )
            {
                HttpResponse response = HttpContext.Current.Response;
                response.Clear();
                response.Charset = "utf-8";
                response.ContentType = "text/plain";
                response.AddHeader( "content-disposition" , string.Format( "attachment; filename={0}" , fileName ) );
                response.BinaryWrite( Encoding.UTF8.GetBytes( txt ) );
                response.End();
            }
        }

        /// <summary>
        /// Write XLS file to response
        /// </summary>
        /// <param name="filePath">File path</param>
        /// <param name="targetFileName">Target file name</param>
        public static void WriteResponseXls( string filePath , string targetFileName )
        {
            if ( !String.IsNullOrEmpty( filePath ) )
            {
                HttpResponse response = HttpContext.Current.Response;
                response.Clear();
                response.Charset = "utf-8";
                response.ContentType = "text/xls";
                response.AddHeader( "content-disposition" , string.Format( "attachment; filename={0}" , targetFileName ) );
                response.BinaryWrite( File.ReadAllBytes( filePath ) );
                response.End();
            }
        }

        /// <summary>
        /// Write PDF file to response
        /// </summary>
        /// <param name="filePath">File napathme</param>
        /// <param name="targetFileName">Target file name</param>
        /// <remarks>For BeatyStore project</remarks>
        public static void WriteResponsePdf( string filePath , string targetFileName )
        {
            if ( !String.IsNullOrEmpty( filePath ) )
            {
                HttpResponse response = HttpContext.Current.Response;
                response.Clear();
                response.Charset = "utf-8";
                response.ContentType = "text/pdf";
                response.AddHeader( "content-disposition" , string.Format( "attachment; filename={0}" , targetFileName ) );
                response.BinaryWrite( File.ReadAllBytes( filePath ) );
                response.End();
            }
        }

        #endregion

        #region Bytes

        /// <summary>
        /// Converts the passed byte array to a string
        /// </summary>
        /// <param name="arrInput">The byte array to convert to a string</param>
        /// <returns></returns>
        public static string ByteArrayToString( byte[] arrInput )
        {
            StringBuilder sOutput = new StringBuilder( arrInput.Length * 2 );
            for ( int i = 0 ; i < arrInput.Length ; i++ )
                sOutput.Append( arrInput[i].ToString( "x2" ) );

            return sOutput.ToString();
        }

        /// <summary>
        /// Converts the passed string to a byte array.
        /// </summary>
        /// <param name="str">The string to convert to a byte array</param>
        /// <returns></returns>
        public static byte[] StringToByteArray( string str )
        {
            Encoding ascii = Encoding.ASCII;
            Encoding unicode = Encoding.Unicode;

            byte[] unicodeBytes = unicode.GetBytes( str );
            byte[] asciiBytes = Encoding.Convert( unicode , ascii , unicodeBytes );
            return asciiBytes;
        }

        #endregion

        #region Lists

        /// <summary>
        /// Convert enum for front-end
        /// </summary>
        /// <param name="str">Input string</param>
        /// <returns>Covnerted string</returns>
        public static string ConvertEnum( string str )
        {
            string result = string.Empty;
            char[] letters = str.ToCharArray();
            foreach ( char c in letters )
                if ( c.ToString() != c.ToString().ToLower() )
                    result += " " + c.ToString();
                else
                    result += c.ToString();
            return result;
        }

        /// <summary>
        /// Fills drop down list with values of enumaration
        /// </summary>
        /// <param name="list">Dropdownlist</param>
        /// <param name="enumType">Enumeration</param>
        public static void FillDropDownWithEnum( DropDownList list , Type enumType )
        {
            if ( list == null )
            {
                throw new ArgumentNullException( "list" );
            }
            if ( enumType == null )
            {
                throw new ArgumentNullException( "enumType" );
            }
            if ( !enumType.IsEnum )
            {
                throw new ArgumentException( "enumType must be enum type" );
            }

            list.Items.Clear();
            string[] strArray = Enum.GetNames( enumType );
            foreach ( string str2 in strArray )
            {
                int enumValue = (int)Enum.Parse( enumType , str2 , true );
                ListItem ddlItem = new ListItem( ConvertEnum( str2 ) , enumValue.ToString() );
                list.Items.Add( ddlItem );
            }
        }

        /// <summary>
        /// Loads the drop down.
        /// </summary>
        /// <param name="ddl">The DDL.</param>
        /// <param name="collection">The collection.</param>
        /// <param name="textField">The text field.</param>
        /// <param name="valueField">The value field.</param>
        /// <param name="initialSelection">The initial selection.</param>
        public static void LoadListControl( ListControl ddl , ICollection collection , string textField , string valueField , string initialSelection )
        {
            ddl.DataSource = collection;
            ddl.DataTextField = textField;
            ddl.DataValueField = valueField;
            ddl.DataBind();

            ddl.SelectedValue = initialSelection;
        }

        /// <summary>
        /// Loads the drop down.
        /// </summary>
        /// <param name="ddl">The DDL.</param>
        /// <param name="collection">The collection.</param>
        /// <param name="textField">The text field.</param>
        /// <param name="valueField">The value field.</param>
        /// <param name="initialSelection">The initial selection.</param>
        public static void LoadListControl( ListControl ddl , ICollection collection , string textField , string valueField )
        {
            ddl.DataSource = collection;
            ddl.DataTextField = textField;
            ddl.DataValueField = valueField;
            ddl.DataBind();
        }

        /// <summary>
        /// Loads the drop down.
        /// </summary>
        /// <param name="listControl">The list control.</param>
        /// <param name="dataReader">The data reader.</param>
        /// <param name="closeReader">if set to <c>true</c> [close reader].</param>
        public static void LoadListControl( ListControl listControl , IDataReader dataReader , bool closeReader )
        {
            listControl.Items.Clear();

            if ( closeReader )
            {
                using ( dataReader )
                {
                    while ( dataReader.Read() )
                    {
                        string sText = dataReader[1].ToString();
                        string sVal = dataReader[0].ToString();
                        listControl.Items.Add( new ListItem( sText , sVal ) );
                    }
                    dataReader.Close();
                }
            }
            else
            {
                while ( dataReader.Read() )
                {
                    string sText = dataReader[1].ToString();
                    string sVal = dataReader[0].ToString();
                    listControl.Items.Add( new ListItem( sText , sVal ) );
                }
            }
        }

        /// <summary>
        /// Loads the list items.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="tblBind">The TBL bind.</param>
        /// <param name="tblVals">The TBL vals.</param>
        /// <param name="textField">The text field.</param>
        /// <param name="valField">The val field.</param>
        public static void LoadListItems( ListItemCollection list , DataTable tblBind , DataTable tblVals , string textField , string valField )
        {
            for ( int i = 0 ; i < tblBind.Rows.Count ; i++ )
            {
                ListItem l = new ListItem( tblBind.Rows[i][textField].ToString() , tblBind.Rows[i][valField].ToString() );

                for ( int x = 0 ; x < tblVals.Rows.Count ; x++ )
                {
                    DataRow dr = tblVals.Rows[x];
                    if ( Strings.Matches( dr[valField].ToString() , l.Value ) )
                        l.Selected = true;
                }
                list.Add( l );
            }
        }

        /// <summary>
        /// Loads the list items.
        /// </summary>
        /// <param name="listCollection">The list.</param>
        /// <param name="dataReader">The data reader.</param>
        /// <param name="textField">The text field.</param>
        /// <param name="valueField">The value field.</param>
        /// <param name="selectedValue">The selected value.</param>
        /// <param name="closeReader">if set to <c>true</c> [close reader].</param>
        public static void LoadListItems( ListItemCollection listCollection , IDataReader dataReader , string textField , string valueField , string selectedValue , bool closeReader )
        {
            listCollection.Clear();

            if ( closeReader )
            {
                using ( dataReader )
                {
                    while ( dataReader.Read() )
                    {
                        string sText = dataReader[textField].ToString();
                        string sVal = dataReader[valueField].ToString();

                        ListItem l = new ListItem( sText , sVal );
                        if ( !String.IsNullOrEmpty( selectedValue ) )
                            l.Selected = Strings.Matches( selectedValue , sVal );
                        listCollection.Add( l );
                    }
                    dataReader.Close();
                }
            }
            else
            {
                while ( dataReader.Read() )
                {
                    string sText = dataReader[textField].ToString();
                    string sVal = dataReader[valueField].ToString();

                    ListItem l = new ListItem( sText , sVal );
                    if ( !String.IsNullOrEmpty( selectedValue ) )
                        l.Selected = Strings.Matches( selectedValue , sVal );
                    listCollection.Add( l );
                }
            }
        }

        /// <summary>
        /// Sets the list selection.
        /// </summary>
        /// <param name="lc">The lc.</param>
        /// <param name="Selection">The selection.</param>
        public static void SetListSelection( ListItemCollection lc , string Selection )
        {
            for ( int i = 0 ; i < lc.Count ; i++ )
            {
                if ( lc[i].Value == Selection )
                {
                    lc[i].Selected = true;
                    break;
                }
            }
        }

        /// <summary>
        /// Selects item
        /// </summary>
        /// <param name="list">List</param>
        /// <param name="value">Value to select</param>
        public static void SelectListItem( DropDownList list , object value )
        {
            if ( list.Items.Count != 0 )
            {
                var selectedItem = list.SelectedItem;
                if ( selectedItem != null )
                    selectedItem.Selected = false;
                if ( value != null )
                {
                    selectedItem = list.Items.FindByValue( value.ToString() );
                    if ( selectedItem != null )
                        selectedItem.Selected = true;
                }
            }
        }

        /// <summary>
        /// Hashtable Compare( Hashtable previousHT , Hashtable newHT )
        /// </summary>
        /// <param name="previousHT">previousHT</param>
        /// <param name="newHT">newHT</param>
        /// <returns>Hashtable</returns>
        public static Hashtable Compare( Hashtable previousHT , Hashtable newHT )
        {
            Hashtable results = new Hashtable();

            foreach ( DictionaryEntry de in newHT )
            {
                if ( !( previousHT.ContainsKey( de.Key ) || previousHT.ContainsValue( de.Value ) ) )
                {
                    results.Add( de.Key , de.Value );
                }
            }

            return results;
        }

        #endregion

        #region Utility

        /// <summary>
        /// Returns an Object with the specified Type and whose value is equivalent to the specified object.
        /// </summary>
        /// <param name="value">An Object that implements the IConvertible interface.</param>
        /// <returns>
        /// An object whose Type is conversionType (or conversionType's underlying type if conversionType
        /// is Nullable&lt;&gt;) and whose value is equivalent to value. -or- a null reference, if value is a null
        /// reference and conversionType is not a value type.
        /// </returns>
        /// <remarks>
        /// This method exists as a workaround to System.Convert.ChangeType(Object, Type) which does not handle
        /// nullables as of version 2.0 (2.0.50727.42) of the .NET Framework. The idea is that method will
        /// be deleted once Convert.ChangeType is updated in a future version of the .NET Framework to handle
        /// nullable types, so we want to behave as closely to Convert.ChangeType as possible.
        /// This method was written by Peter Johnson at:
        /// http://aspalliance.com/author.aspx?uId=1026.
        /// </remarks>
        /// 
        public static object ChangeTypeTo<T>(object value)
        {
            Type conversionType = typeof(T);
            return ChangeTypeTo(value, conversionType);
        }

        public static object ChangeTypeTo(object value, Type conversionType)
        {
            // Note: This if block was taken from Convert.ChangeType as is, and is needed here since we're
            // checking properties on conversionType below.
            if (conversionType == null)
                throw new ArgumentNullException("conversionType");

            // If it's not a nullable type, just pass through the parameters to Convert.ChangeType

            if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                // It's a nullable type, so instead of calling Convert.ChangeType directly which would throw a
                // InvalidCastException (per http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx),
                // determine what the underlying type is
                // If it's null, it won't convert to the underlying type, but that's fine since nulls don't really
                // have a type--so just return null
                // Note: We only do check if we're converting to a nullable type, since doing it outside
                // would diverge from Convert.ChangeType's behavior, which throws an InvalidCastException if
                // value is null and conversionType is a value type.
                if (value == null)
                    return null;

                // It's a nullable type, and not null, so that means it can be converted to its underlying type,
                // so overwrite the passed-in conversion type with underlying type
                NullableConverter nullableConverter = new NullableConverter(conversionType);
                conversionType = nullableConverter.UnderlyingType;
            }
            else if (conversionType == typeof(Guid))
            {
                return new Guid(value.ToString());

            }
            else if (conversionType == typeof(Int64) && value.GetType() == typeof(int))
            {
                //there is an issue with SQLite where the PK is ALWAYS int64. If conversion type is Int64
                //we need to throw here - suggesting that they need to use LONG instead


                throw new InvalidOperationException("Can't convert an Int64 (long) to Int32(int). If you're using SQLite - is probably due to your PK being an INTEGER, which is 64bit. You'll need to set your key to long.");
            }

            // Now that we've guaranteed conversionType is something Convert.ChangeType can handle (i.e. not a
            // nullable type), pass the call on to Convert.ChangeType
            return Convert.ChangeType(value, conversionType);
        }

        public static Dictionary<string, object> ToDictionary(object value)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            PropertyInfo[] props = value.GetType().GetProperties();
            foreach (PropertyInfo pi in props)
            {
                try
                {
                    result.Add(pi.Name, pi.GetValue(value, null));
                }
                catch { }
            }
            return result;
        }

        public static T FromDictionary<T>(Dictionary<string, object> settings, T item) where T : class
        {
            PropertyInfo[] props = item.GetType().GetProperties();
            //FieldInfo[] fields = item.GetType().GetFields();
            foreach (PropertyInfo pi in props)
            {
                if (settings.ContainsKey(pi.Name))
                {
                    if (pi.CanWrite)
                        pi.SetValue(item, settings[pi.Name], null);
                }
            }
            return item;
        }

        public static T CopyTo<T>(object From, T to) where T : class
        {
            Type t = From.GetType();

            var settings = ToDictionary(From);

            to = FromDictionary(settings, to);

            return to;
        }

        private static bool CanGenerateSchemaFor(Type type)
        {
            return type == typeof(string) ||
                   type == typeof(Guid) ||
                   type == typeof(Guid?) ||
                   type == typeof(decimal) ||
                   type == typeof(decimal?) ||
                   type == typeof(double) ||
                   type == typeof(double?) ||
                   type == typeof(DateTime) ||
                   type == typeof(DateTime?) ||
                   type == typeof(bool) ||
                   type == typeof(bool?) ||
                   type == typeof(Int16) ||
                   type == typeof(Int16?) ||
                   type == typeof(Int32) ||
                   type == typeof(Int32?) ||
                   type == typeof(Int64) ||
                   type == typeof(Int64?) ||
                   type == typeof(float?) ||
                   type == typeof(float) ||
                   type == typeof(byte[]) ||
                   type.IsEnum || IsNullableEnum(type);
        }

        internal static bool IsNullableEnum(Type type)
        {
            var enumType = Nullable.GetUnderlyingType(type);

            return enumType != null && enumType.IsEnum;
        }

        #endregion
    }
}

